package com.itcs.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.HashedWheelTimer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;

import java.util.concurrent.TimeUnit;

/**
 * 
 * @author LiuPeng
 * 
 */
// @Component
public class NettyClientBootstrap implements InitializingBean {

	private Log logger = LogFactory.getLog(NettyClientBootstrap.class);

	protected final HashedWheelTimer timer = new HashedWheelTimer();

	private String host;

	private int port;

	private String clientId;

	private Bootstrap bootstrap;
	private ConnectionWatchdog watchdog;
	private SocketChannel socketChannel;

	private boolean connected = false;

	public NettyClientBootstrap(String host, int port, String clientId) {
		this.host = host;
		this.port = port;
		this.clientId = clientId;
	}

	private void initBootstrap() throws InterruptedException {
		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
		bootstrap = new Bootstrap();
		bootstrap.channel(NioSocketChannel.class);
		bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
		bootstrap.group(eventLoopGroup);
		watchdog = new ConnectionWatchdog(this, timer) {
			public ChannelHandler[] handlers() {
				return new ChannelHandler[] { this, new IdleStateHandler(30, 30, 0, TimeUnit.SECONDS),
						new ObjectEncoder(), new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
						new NettyClientHandler() };
			}
		};
	}

	public SocketChannel getSocketChannel() {
		return socketChannel;
	}

	public void start() throws InterruptedException {
		initBootstrap();// 初始化
		connect(watchdog);// 连接
	}

	public void connect(final ConnectionWatchdog watchdog) {
		ChannelFuture future;
//		synchronized (bootstrap) {
			bootstrap.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {
					socketChannel.pipeline().addLast(watchdog.handlers());
				}
			});
			future = bootstrap.connect(host, port);
//		}

		// future对象
		future.addListener(new ChannelFutureListener() {
			public void operationComplete(ChannelFuture f) throws Exception {
				boolean succeed = f.isSuccess();
				if (succeed) {
					// logger.info("连接服务器成功...");
					socketChannel = (SocketChannel) f.channel();
//					login();
				} else {
					logger.info("client[" + clientId + "]连接服务器失败...");
					f.channel().pipeline().fireChannelInactive();
				}
			}
		});
	}

//	public void login() {
//		logger.info("发送登陆登陆服务器请求....");
//		BaseMsg loginMsg = new BaseMsg(MsgType.LOGIN);
//		loginMsg.setClientId(this.clientId);
//		socketChannel.writeAndFlush(loginMsg);
//	}

	public void writeAndFlush(Object reqObj) {
		if (socketChannel != null) {
			socketChannel.writeAndFlush(reqObj);
		}
	}

	public boolean isConnected() {
		return connected;
	}

	public void setConnected(boolean connected) {
		this.connected = connected;
	}

	public String getClientId() {
		return clientId;
	}

	@Override
	public void afterPropertiesSet() throws Exception {

	}
}
